package com.apes.fico.finance.service;

import com.apes.fico.finance.model.gl.*;
import com.apes.fico.finance.respository.ChartAmoutRepository;
import com.apes.fico.finance.respository.ChartAuxRepository;
import com.apes.fico.finance.respository.InitAuxRepository;
import com.apes.fico.finance.respository.InitBalanceRepository;
import com.apes.fico.masterdata.gl.model.AccountingOperatingChart;
import com.apes.fico.masterdata.gl.respository.AccountingOperatingChartAuxiliaryRepository;
import com.apes.framework.api.DomainService;
import com.apes.framework.api.SpringManager;
import com.apes.framework.jpa.spec.JpaDsl;
import com.apes.framework.plugin.esb.api.SimpleRequest;
import com.apes.framework.util.JpaUtil;
import com.apes.scm.masterdata.party.model.PartyRole;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;


/**
 * @ClassName ChartService
 * @Description 当期发生额
 * @Author pengyb
 * @Date 2019/1/17 10:30
 * @Version 1.0
 */
@Service("chartService")
public class ChartService extends DomainService {

    @Autowired
    private ChartAmoutRepository chartAmoutRepository;
    @Autowired
    private ChartAuxRepository chartAuxRepository;
    @Autowired
    private InitBalanceRepository initBalanceRepository;
    @Autowired
    private InitAuxRepository initAuxRepository;

    /**
     * 写入每期科目发生额（无辅助核算）
     * @param company  公司
     * @param accountingOperatingChart  科目
     * @param year  会计年度
     * @param period  会计期间
     * @param changeUnDebit  未记账借方发生金额
     * @param changeUnCredit 未记账贷方发生金额
     * @param changeDebit  借方发生金额
     * @param changeCredit  贷方发生金额
     * @param voucherId 财务凭证编号
     * @param voucherItemId 财务凭证明细编号
     * @param remarks  备注
     * @return  ChartAmount
     */
    public ChartAmount saveChartAmount(PartyRole company, AccountingOperatingChart accountingOperatingChart, int year, int period,
                                       double changeUnDebit, double changeUnCredit, double changeDebit, double changeCredit,
                                       String voucherId, String voucherItemId, String remarks) {
        ChartAmount chartAmount = chartAmoutRepository.findOne(JpaDsl.toCriteriaByEq("company", company,
                "accountingOperatingChart", accountingOperatingChart, "year", year, "period", period)).orElse(null);
        if (chartAmount == null) {
            chartAmount = new ChartAmount();
            chartAmount.setCompany(company);
            chartAmount.setAccountingOperatingChart(accountingOperatingChart);
            chartAmount.setYear(year);
            chartAmount.setPeriod(period);
        }
        chartAmount.changeUnDebit(changeUnDebit);
        chartAmount.changeUnCredit(changeUnCredit);
        chartAmount.changeDebit(changeDebit);
        chartAmount.changeCredit(changeCredit);
        chartAmount = chartAmoutRepository.saveAndFlush(chartAmount);

        saveChartAccount(company, accountingOperatingChart, year, period, changeUnDebit, changeUnCredit, changeDebit, changeCredit,
                voucherId, voucherItemId, remarks, chartAmount.getId(), false, chartAmount.getUnDebit(),
                chartAmount.getUnCredit(), chartAmount.getDebit(), chartAmount.getCredit());

        return chartAmount;
    }

    /**
     * 写入每期科目发生额（有辅助核算）
     * @param company  公司
     * @param accountingOperatingChart  科目
     * @param year  会计年度
     * @param period  会计期间
     * @param key  辅助核算
     * @param name  辅助内容
     * @param chartAuxItems 辅助核算明细
     * @param changeUnDebit  未记账借方发生金额
     * @param changeUnCredit 未记账贷方发生金额
     * @param changeDebit  借方发生金额
     * @param changeCredit  贷方发生金额
     * @param voucherId 财务凭证编号
     * @param voucherItemId 财务凭证明细编号
     * @param remarks  备注
     * @return  ChartAmount
     */
    public ChartAux saveChartAux(PartyRole company, AccountingOperatingChart accountingOperatingChart, int year, int period, String key, String name,
                                 List<Map> chartAuxItems, double changeUnDebit, double changeUnCredit, double changeDebit, double changeCredit,
                                 String voucherId, String voucherItemId, String remarks) {
        ChartAux chartAux = chartAuxRepository.findOne(JpaDsl.toCriteriaByEq("company", company,
                "accountingOperatingChart", accountingOperatingChart, "year", year, "period", period, "key", key)).orElse(null);
        if (chartAux == null) {
            chartAux = new ChartAux();
            chartAux.setCompany(company);
            chartAux.setAccountingOperatingChart(accountingOperatingChart);
            chartAux.setYear(year);
            chartAux.setPeriod(period);
            chartAux.setKey(key);
            chartAux.setName(name);
            List<ChartAuxItem> chartAuxItemList = new ArrayList<>();
            AccountingOperatingChartAuxiliaryRepository repository = SpringManager.getBean(AccountingOperatingChartAuxiliaryRepository.class);
            for (Map row : chartAuxItems) {
                ChartAuxItem item = new ChartAuxItem();
                item.setChartAux(chartAux);
                item.setAccountingOperatingChartAuxiliary(repository.findOne((String) row.get("aocaId")));
                item.setCode((String) row.get("code"));
                item.setName((String) row.get("name"));
                chartAuxItemList.add(item);
            }
            chartAux.setChartAuxItemList(chartAuxItemList);
        }
        chartAux.changeUnDebit(changeUnDebit);
        chartAux.changeUnCredit(changeUnCredit);
        chartAux.changeDebit(changeDebit);
        chartAux.changeCredit(changeCredit);
        chartAux = chartAuxRepository.saveAndFlush(chartAux);

        saveChartAccount(company, accountingOperatingChart, year, period, changeUnDebit, changeUnCredit, changeDebit, changeCredit,
                voucherId, voucherItemId, remarks, chartAux.getId(), true, chartAux.getUnDebit(),
                chartAux.getUnCredit(), chartAux.getDebit(), chartAux.getCredit());

        return chartAux;
    }

    /**
     * 保存科目余额明细帐
     * @param company 公司
     * @param accountingOperatingChart 科目
     * @param year 会计年度
     * @param period 会计期间
     * @param changeUnDebit 未记账借方变动金额
     * @param changeUnCredit 未记账贷方变动金额
     * @param changeDebit 借方变动金额
     * @param changeCredit 贷方变动金额
     * @param voucherId 财务凭证编号
     * @param voucherItemId 财务凭证明细编号
     * @param remarks 备注
     * @param chartId 科目余额帐
     * @param auxed 是否辅助科目
     * @param unDebit 未记账借方期末余额
     * @param unCredit 未记账贷方期末余额
     * @param debit 借方期末余额
     * @param credit 贷方期末余额
     */
    private void saveChartAccount(PartyRole company, AccountingOperatingChart accountingOperatingChart, int year, int period,
                                  double changeUnDebit, double changeUnCredit, double changeDebit, double changeCredit,
                                  String voucherId, String voucherItemId, String remarks, String chartId, boolean auxed,
                                  double unDebit, double unCredit, double debit, double credit) {
        ChartAccount chartAccount = new ChartAccount();
        chartAccount.setCompany(company);
        chartAccount.setAccountingOperatingChart(accountingOperatingChart);
        chartAccount.setYear(year);
        chartAccount.setPeriod(period);
        chartAccount.setChartId(chartId);
        chartAccount.setAuxed(auxed);
        chartAccount.setVoucherId(voucherId);
        chartAccount.setVoucherItemId(voucherItemId);
        chartAccount.setRemarks(remarks);
        chartAccount.setChangeUnDebit(changeUnDebit);
        chartAccount.setUnDebit(unDebit);
        chartAccount.setChangeUnCredit(changeUnCredit);
        chartAccount.setUnCredit(unCredit);
        chartAccount.setChangeDebit(changeDebit);
        chartAccount.setDebit(debit);
        chartAccount.setChangeCredit(changeCredit);
        chartAccount.setCredit(credit);
        JpaUtil.getRepository(ChartAccount.class).save(chartAccount);
    }

    /**
     * 无辅助核算月结
     *
     * @param request
     * @return
     */
    public ChartAmount chartAmountMonthly(SimpleRequest request) {
        ChartAmount chartAmount = request.getO(ChartAmount.class);
        ChartAmount amount = new ChartAmount();
        if (chartAmount.getPeriod() % 100  == 12) { //本年度最后一月时，向下一年一月结转
            amount.setYear(chartAmount.getYear() + 1);
            amount.setPeriod(chartAmount.getPeriod() + 89);
        } else {
            amount.setYear(chartAmount.getYear());
            amount.setPeriod(chartAmount.getPeriod() + 1);
        }
        amount.setOpeningBalance((chartAmount.getDebit() - chartAmount.getCredit()) + chartAmount.getOpeningBalance());
        amount.setCompany(chartAmount.getCompany());
        amount.setAccountingOperatingChart(chartAmount.getAccountingOperatingChart());
        if (chartAmount.getPeriod() % 100  == 12) { //转入年初余额
            writeInit(amount, false);
        }
        ChartAmount chart = chartAmoutRepository.findByCompany_IdAndPeriodAndAccountingOperatingChart_Id(chartAmount.getCompany().getId(), amount.getPeriod(), chartAmount.getAccountingOperatingChart().getId());
        if (chart != null) {
            chart.setOpeningBalance((chartAmount.getDebit() - chartAmount.getCredit()) + chartAmount.getOpeningBalance());
            return chartAmoutRepository.saveAndFlush(chart);
        }
        return chartAmoutRepository.saveAndFlush(amount);
    }

    /**
     * 有辅助核算月结
     *
     * @param request
     * @return
     */
    public ChartAux chartAuxMonthly(SimpleRequest request) {
        ChartAux chartAux = request.getO(ChartAux.class);
        ChartAux aux = new ChartAux();
        if (chartAux.getPeriod() % 100 == 12) {
            aux.setYear(chartAux.getYear() + 1);
            aux.setPeriod(chartAux.getPeriod() + 89);
        } else {
            aux.setYear(chartAux.getYear());
            aux.setPeriod(chartAux.getPeriod() + 1);
        }

        aux.getChartAuxItemList().addAll(chartAux.getChartAuxItemList());
        aux.setOpeningBalance((chartAux.getDebit() - chartAux.getCredit()) + chartAux.getOpeningBalance());
        aux.setCompany(chartAux.getCompany());
        aux.setAccountingOperatingChart(chartAux.getAccountingOperatingChart());
        aux.setKey(chartAux.getKey());
        aux.setName(chartAux.getName());

        if (chartAux.getPeriod() % 100 == 12) { //转入年初余额
            writeInit(aux, true);
        }
        ChartAux chart = chartAuxRepository.findByCompany_IdAndPeriodAndAccountingOperatingChart_IdAndKey(chartAux.getCompany().getId(), aux.getPeriod(), chartAux.getAccountingOperatingChart().getId(),chartAux.getKey());
        if (chart != null) {
            chart.setOpeningBalance((chartAux.getDebit() - chartAux.getCredit()) + chartAux.getOpeningBalance());
            return chartAuxRepository.saveAndFlush(chart);
        }
        return chartAuxRepository.saveAndFlush(aux);
    }

    /**
     * 取消月结(无辅助核算)
     *
     * @param request
     * @return
     */
    public ChartAmount chartAmountCancelMonthly(SimpleRequest request) {
        ChartAmount chartAmount = request.getO(ChartAmount.class);
        chartAmount.setOpeningBalance(0);
        return chartAmoutRepository.saveAndFlush(chartAmount);
    }

    /**
     * 取消月结(有辅助核算)
     *
     * @param request
     * @return
     */
    public ChartAux chartAuxCancelMonthly(SimpleRequest request) {
        ChartAux chartAux = request.getO(ChartAux.class);
        chartAux.setOpeningBalance(0);
        return chartAuxRepository.saveAndFlush(chartAux);
    }

    /**
     * 取消月结时,年初余额归零
     * @param companyId 公司
     * @param period 会计期间
     */
    public void cancelWriteInit(int period,String companyId) {
        initAuxRepository.updateOpenBalanceByPeriodAndCompany_Id(period,companyId);
        initBalanceRepository.updateOpenBalanceByPeriodAndCompany_Id(period,companyId);
    }


    /**
     * 写入年初余额
     *
     * @param o
     * @param flag
     */
    public void writeInit(Object o, boolean flag) {
        if (flag) {
            ChartAux chartAux = (ChartAux) o;
            InitAux aux = initAuxRepository.findByCompany_IdAndPeriodAndAccountingOperatingChart_IdAndKey(chartAux.getCompany().getId(), chartAux.getPeriod(), chartAux.getAccountingOperatingChart().getId(),chartAux.getKey());
            if (aux != null) {
                aux.setOpeningBalance(chartAux.getOpeningBalance());
                initAuxRepository.saveAndFlush(aux);
            } else {
                InitAux initAux = new InitAux();
                initAux.setCompany(chartAux.getCompany());
                initAux.setCredit(chartAux.getCredit());
                initAux.setDebit(chartAux.getDebit());
                initAux.setUnCredit(chartAux.getUnCredit());
                initAux.setUnDebit(chartAux.getUnDebit());
                initAux.setYear(chartAux.getYear());
                initAux.setAccountingOperatingChart(chartAux.getAccountingOperatingChart());
                initAux.setPeriod(chartAux.getPeriod());
                initAux.setOpeningBalance(chartAux.getOpeningBalance());
                initAux.setKey(chartAux.getKey());
                initAux.setName(chartAux.getName());
                initAux.getInitAuxItemList().clear();
                List<InitAuxItem> initAuxItems = new ArrayList<>();
                chartAux.getChartAuxItemList().forEach(chartAuxItem -> {
                    InitAuxItem item = new InitAuxItem();
                    item.setCode(chartAuxItem.getCode());
                    item.setName(chartAuxItem.getName());
                    item.setAccountingOperatingChartAuxiliary(chartAuxItem.getAccountingOperatingChartAuxiliary());
                    initAuxItems.add(item);
                });
                initAux.getInitAuxItemList().addAll(initAuxItems);
                initAuxRepository.saveAndFlush(initAux);
            }
        } else {
            ChartAmount chartAmount = (ChartAmount) o;
            InitBalance balance = initBalanceRepository.findByCompany_IdAndPeriodAndAccountingOperatingChart_Id(chartAmount.getCompany().getId(), chartAmount.getPeriod(), chartAmount.getAccountingOperatingChart().getId());
            if (balance != null) {
                balance.setOpeningBalance(chartAmount.getOpeningBalance());
                initBalanceRepository.saveAndFlush(balance);
            } else {
                InitBalance initBalance = new InitBalance();
                initBalance.setCompany(chartAmount.getCompany());
                initBalance.setCredit(chartAmount.getCredit());
                initBalance.setDebit(chartAmount.getDebit());
                initBalance.setUnCredit(chartAmount.getUnCredit());
                initBalance.setUnDebit(chartAmount.getUnDebit());
                initBalance.setYear(chartAmount.getYear());
                initBalance.setAccountingOperatingChart(chartAmount.getAccountingOperatingChart());
                initBalance.setPeriod(chartAmount.getPeriod());
                initBalance.setOpeningBalance(chartAmount.getOpeningBalance());
                initBalanceRepository.saveAndFlush(initBalance);
            }
        }
    }
}
